/*******************************************************************************
 * Copyright (c) 2011 Prometheus Consulting
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *******************************************************************************/

package nz.co.senanque.vaadinsupport.viewmanager;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Stack;

import javax.servlet.http.HttpSession;

import nz.co.senanque.vaadinsupport.I18n.I18nCaptionHelper;
import nz.co.senanque.vaadinsupport.application.MaduraSessionManager;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.support.MessageSourceAccessor;

import com.vaadin.Application;
import com.vaadin.terminal.gwt.server.WebApplicationContext;
import com.vaadin.ui.Component;
import com.vaadin.ui.ComponentContainer;
import com.vaadin.ui.Panel;
import com.vaadin.ui.Window;

/**
 * 
 * Original idea came from from http://dev.vaadin.com/browser/incubator/gasdiary/src/org/vaadin/gasdiary/ui/ViewManager.java
 * Because it is accessible from non-spring beans (using a factory) it is used to hold various
 * view related stuff as well as the views. It should be wired as a session scoped bean.
 * 
 * @author Roger Parkinson
 * @version $Revision:$
 */
//@org.springframework.stereotype.Component
public class ViewManagerImpl implements InitializingBean, ViewManager, Serializable, MessageSourceAware {
    
	private static final long serialVersionUID = -2928146002699266524L;
	private static Logger logger = LoggerFactory.getLogger(ViewManagerImpl.class);
	private HashMap<String, ComponentContainer> views = new HashMap<String, ComponentContainer>();
    private final Stack<ComponentContainer> screenStack = new Stack<ComponentContainer>();
    private List<ViewManaged> initialLayouts = new ArrayList<ViewManaged>(); 
    private List<ViewManaged> applicationLayouts = new ArrayList<ViewManaged>(); 
    private Window m_mainWindow = new com.vaadin.ui.Window();
	private Application m_application;
	private int m_debugCounter=0;
	private MaduraSessionManager m_maduraSessionManager;
	private boolean m_adjustCaptions = false;
	private MessageSourceAccessor m_messageSourceAccessor;

	public ViewManagerImpl () {
    }
    
    /**
     * Switches current screen to the given screen.
     * 
     * @param screenType
     *            The screen to switch to.
     * @param newScreen
     *            If not null, the existing screen is replaced with the given
     *            screen.
     */
    public void switchScreen(String viewName, ComponentContainer newView) {
    	ComponentContainer view;
        if (newView != null) {
            view = newView;
            views.put(viewName, newView);
        } else
            view = views.get(viewName);
        getMainWindow().setContent(view);
    }
    
    public void switchScreen(String viewName) {
        switchScreen(viewName,null);
    }
    
    /* (non-Javadoc)
     * @see nz.co.senanque.vaadinsupport.viewmanager.ViewManager#pushScreen(java.lang.String, com.vaadin.ui.ComponentContainer)
     */
    public void pushScreen(String viewName, ComponentContainer newView) {
        screenStack.push((ComponentContainer) getMainWindow().getContent());
        switchScreen(viewName, newView);
    }

    /* (non-Javadoc)
     * @see nz.co.senanque.vaadinsupport.viewmanager.ViewManager#pushScreen(java.lang.String)
     */
    public void pushScreen(String viewName) {
    	ComponentContainer target =  get(viewName);
        pushScreen(viewName,target);
    }

    /* (non-Javadoc)
     * @see nz.co.senanque.vaadinsupport.viewmanager.ViewManager#popScreen()
     */
    public void popScreen() {
    	getMainWindow().setContent(screenStack.pop());
    }
    
    /* (non-Javadoc)
     * @see nz.co.senanque.vaadinsupport.viewmanager.ViewManager#getWindow()
     */
    public Panel getWindow() {
        return getMainWindow();
    }

    /* (non-Javadoc)
     * @see nz.co.senanque.vaadinsupport.viewmanager.ViewManager#put(java.lang.String, com.vaadin.ui.ComponentContainer)
     */
    public void put(String name, ComponentContainer layout)
    {
        views.put(name, layout);
    }

    /* (non-Javadoc)
     * @see nz.co.senanque.vaadinsupport.viewmanager.ViewManager#get(java.lang.String)
     */
    public ComponentContainer get(String name)
    {
        return views.get(name);
    }

	public void afterPropertiesSet() throws Exception {
		getMainWindow().setCaption(m_messageSourceAccessor.getMessage("title", null,"title"));
		for (ViewManaged viewManaged: getInitialLayouts())
		{
			views.put(viewManaged.getClass().getName(), (ComponentContainer)viewManaged);
			if (isAdjustCaptions())
			{
				I18nCaptionHelper.switchCaptions((Component)viewManaged, m_messageSourceAccessor);
			}
			viewManaged.setViewManager(this);
		}
	}

	/* (non-Javadoc)
     * @see nz.co.senanque.vaadinsupport.viewmanager.ViewManager#getViews()
     */
	public HashMap<String, ComponentContainer> getViews() {
		return views;
	}

	public void setViews(HashMap<String, ComponentContainer> views) {
		this.views = views;
	}

	/* (non-Javadoc)
     * @see nz.co.senanque.vaadinsupport.viewmanager.ViewManager#getMainWindow()
     */
	public Window getMainWindow() {
		return m_mainWindow;
	}

	public void setMainWindow(Window mainWindow) {
		m_mainWindow = mainWindow;
	}
	/* (non-Javadoc)
     * @see nz.co.senanque.vaadinsupport.viewmanager.ViewManager#loadApplication()
     */
	public void loadApplication() {
		
		String mainLayout = null;
		logger.debug("debug counter",m_debugCounter++);
		for (ViewManaged viewManaged: getApplicationLayouts())
		{
			views.put(viewManaged.getClass().getName(), (ComponentContainer)viewManaged);
			if (mainLayout == null)
			{
				mainLayout = viewManaged.getClass().getName();
			}
			if (isAdjustCaptions())
			{
				I18nCaptionHelper.switchCaptions((Component)viewManaged, m_messageSourceAccessor);
			}
			viewManaged.setViewManager(this);
		}		
		switchScreen(mainLayout);
		
	}
	/* (non-Javadoc)
     * @see nz.co.senanque.vaadinsupport.viewmanager.ViewManager#logout()
     */
	public void logout() {
    	HttpSession httpSession = ((WebApplicationContext)getApplication().getContext()).getHttpSession();
    	httpSession.invalidate();
    	if (getMaduraSessionManager() != null)
    	{
    		getMaduraSessionManager().close();
    	}
	}
    /* (non-Javadoc)
     * @see nz.co.senanque.vaadinsupport.viewmanager.ViewManager#getInitialLayouts()
     */
    public List<ViewManaged> getInitialLayouts()
    {
        return initialLayouts;
    }
    public void setInitialLayouts(List<ViewManaged> initialLayouts)
    {
        this.initialLayouts = initialLayouts;
    }
    /* (non-Javadoc)
     * @see nz.co.senanque.vaadinsupport.viewmanager.ViewManager#getApplicationLayouts()
     */
    public List<ViewManaged> getApplicationLayouts()
    {
        return applicationLayouts;
    }
    public void setApplicationLayouts(List<ViewManaged> applicationLayouts)
    {
        this.applicationLayouts = applicationLayouts;
    }
    public Application getApplication()
    {
        return m_application;
    }
    public void setApplication(Application application)
    {
        m_application = application;
    }
	public void setMessageSource(MessageSource messageSource) {
		m_messageSourceAccessor = new MessageSourceAccessor(messageSource);
	}
	public MaduraSessionManager getMaduraSessionManager() {
		return m_maduraSessionManager;
	}
	public void setMaduraSessionManager(MaduraSessionManager maduraSessionManager) {
		m_maduraSessionManager = maduraSessionManager;
	}
	public boolean isAdjustCaptions() {
		return m_adjustCaptions;
	}
	public void setAdjustCaptions(boolean adjustCaptions) {
		m_adjustCaptions = adjustCaptions;
	}
}
